<template>
    <el-upload
        list-type="picture-card"
        :class="{ disabled: list.length >= limit }"
        :action="action"
        :multiple="multiple"
        :data="data"
        :accept="accept"
        :limit="limit"
        :file-list="list"
        :before-upload="onBeforeUpload"
        :on-success="onSuccess"
        :on-error="onError"
        :on-remove="onRemove"
        :on-exceed="onExceed"
    >
        <i class="el-icon-plus"></i>
    </el-upload>
</template>

<script>
/**
 * @description 图片上传组件
 *
 * @description props参数
 * @param {array} value - 文件列表
 * @param {string} action - 上传地址
 * @param {object} headers - 上传请求头
 * @param {boolean} multiple - 是否支持多选
 * @param {object} data - 上传时附带的额外参数
 * @param {string} accept - 接受上传的文件类型
 * @param {number} limit - 最大允许上传个数，默认为1
 * @param {string} size - 上传大小限制，可传格式示例：200b、2kb、2M、2MB、2G、2GB，字母大小不限，默认2M
 *
 * @example
 * <upload-img v-model="list" size="500kb"></upload-img>
 */
export default {
    name: "upload-img",
    data() {
        return {
            list: [],
            successList: [], // 当次上传图片地址
        };
    },
    props: {
        value: {
            default: () => [],
        },
        action: {
            type: String,
            default:
                process.env.NODE_ENV == "development"
                    ? "http://192.168.2.145:3001/admin/upload-image"
                    : `${location.origin}/admin/upload-image`,
        },
        headers: {
            type: Object,
            default: () => ({}),
        },
        multiple: {
            type: Boolean,
            default: true,
        },
        data: {
            type: Object,
            default: () => ({ path: "image" }),
        },
        accept: {
            type: String,
            default: "image/*",
        },
        limit: {
            type: Number,
            default: 1,
        },
        size: {
            type: String,
            default: "2M",
        },
    },
    watch: {
        value(n) {
            // 非数组类型
            if (this.$utils.type(n) !== "array") {
                return console.error("uploadImg组件", "v-model数据格式错误");
            }
            // 数组对象中未发现图片地址
            let list = this.list,
                flag = false,
                arr = [];
            this.$utils.each(n, (item) => {
                if (!item.url) {
                    flag = true;
                    return false;
                }
                if (!list.find((value) => value.uid === item.uid)) {
                    arr.push(item);
                }
            });
            if (flag) {
                return console.error(
                    "uploadImg组件",
                    "v-model数据中未找到url数据"
                );
            }
            // 另存地址
            this.list = this.list.concat(arr);
        },
    },
    methods: {
        onBeforeUpload(file) {
            if (!this.action) {
                console.error("未找到图片上传接口");
                return false;
            }
            let size = this.size.toLowerCase(),
                g = size.includes("g"),
                m = size.includes("m"),
                kb = size.includes("kb"),
                num = parseFloat(size);
            if (g) {
                size = num * 1024 * 1024 * 1024;
            } else if (m) {
                size = num * 1024 * 1024;
            } else if (kb) {
                size = num * 1024;
            }
            if (file.size > size) {
                this.$message.error(
                    `所选文件中有超过${this.size}的文件，请重新选择`
                );
                return false;
            }
            return true;
        },
        onSuccess(res, file, fileList) {
            const { data } = res;
            this.successList.push({
                name: file.name,
                uid: file.uid,
                url: data.imageUrl,
            });
            // 判断是否存在File类型（即item.raw），存在则为当次新添加的图片
            if (
                this.successList.length ===
                fileList.filter((item) => !!item.raw).length
            ) {
                // 只设置一次:file-list的值，多次设置会导致值丢失
                this.list = this.list.concat(this.successList);
                // 重置当次已上传图片信息
                this.successList = [];
                this.$emit("input", this.list);
            }
        },
        onError(err, file, fileList) {
            this.$message.error("上传文件失败，请稍后重试");
        },
        onRemove(file, fileList) {
            if (file.status === "success") {
                // :before-upload方法在return false时也会调用:on-remove方法
                // 已上传的图片才可删除
                const index = this.list.findIndex(
                    (item) => item.uid === file.uid
                );
                this.list.splice(index, 1);
                this.$emit("input", this.list);
            }
        },
        onExceed(files, fileList) {
            this.$message.error(`最多可上传${this.limit}个文件，请重新选择`);
        },
    },
};
</script>

<style lang="less" scoped>
.disabled {
    ::v-deep .el-upload--picture-card {
        display: none;
    }
}
// 上传框大小
::v-deep .el-upload--picture-card {
    width: 120px;
    height: 120px;
    line-height: 118px;
}
::v-deep .el-upload-list--picture-card .el-upload-list__item {
    width: 120px;
    height: 120px;
}
// 上传框进度条大小
::v-deep .el-upload-list--picture-card .el-progress {
    width: 120px;
}
::v-deep .el-progress-circle {
    width: 120px !important;
    height: 120px !important;
}
</style>
